using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;
using Felbot.Interface;
using Felbot.Interface.Conversations;
using Felbot.Interface.Users;
using Felbot.IO;
using Felbot.Profiles;
using Felbot.Protocol;

namespace Felbot {
    /// <summary>
    /// This class is the real "bot" of Felbot.
    /// The user interacts directly with these several profile form.
    /// </summary>
    public partial class frmProfile : Form {
        #region Fields and Properties
        private Profile m_Profile;
        private BattleNetPacketThread m_PacketThread;
        private Channel m_Channel;
        private Friends m_Friends;
        private Clan m_Clan;

        private int m_LastPositionL = 0;
        private int m_LastPositionT = 0;
        private int m_LastPositionW = 0;
        private int m_LastPositionH = 0;
        private FormWindowState m_LastState = FormWindowState.Normal;
        private DateTime m_Started = DateTime.Now;

        /// <summary>The instance of the profile this form represents.</summary>
        public Profile Profile {
            get {
                return m_Profile;
            }
        }

        /// <summary>The RichTextBox on this profile form.</summary>
        public RichTextBoxEx RichTextBox {
            get {
                return rtbChat;
            }
        }

        /// <summary>The packet thread used by this profile form.</summary>
        public BattleNetPacketThread PacketThread {
            get {
                return m_PacketThread;
            }
        }

        /// <summary>This class controls the channel list and channel events for this profile form.</summary>
        public Channel Channel {
            get {
                return m_Channel;
            }
        }

        /// <summary>This class controls the friend list and friend events for this profile form.</summary>
        public Friends Friends {
            get {
                return m_Friends;
            }
        }

        /// <summary>This class controls the clan list and clan events for this profile form.</summary>
        public Clan Clan {
            get {
                return m_Clan;
            }
        }

        public static frmProfile GetForm(Profile profile) {
            return GetForm(profile.ProfileName);
        }

        public static frmProfile GetForm(string profileName) {
            foreach (Form form in Program.MainForm.MdiChildren) {
                if (form.GetType().Equals(typeof(frmProfile))) {
                    Profile profile = (form as frmProfile).Profile;
                    if (profile.ProfileName.Equals(profileName, StringComparison.CurrentCultureIgnoreCase)) {
                        return form as frmProfile;
                    }
                }
            }
            return null;
        }
        #endregion

        #region Constructor and Form Events
        /// <summary>Creates a new profile form.</summary>
        /// <param name="main">The parent form.</param>
        /// <param name="a_pProfile">The profile to associate this form with.</param>
        public frmProfile(Profile profile) {
            InitializeComponent();

            m_Profile = profile;
            txtSend.Initialize(this);
            RichTextBox.Initialize(Profile.ProfileName);
            m_PacketThread = new BattleNetPacketThread(this);
            m_Channel = new Channel(this, lvChannel, lblChannel);
            m_Friends = new Friends(this, lvFriends, lblFriends);
            m_Clan = new Clan(this, lvClan, lblClan);

            this.scContainer.Panel1MinSize = 250;
            this.scContainer.Panel2MinSize = 250;

            #region Start-Up Settings
            #region Rich Text Box
            FCSSetting setting = FCSControl.GetCurrentSetting(FCSObjects.Chatroom_Text);
            RichTextBox.ForeColor = setting.ColorFore;
            RichTextBox.BackColor = setting.ColorBack;
            RichTextBox.Font = new Font(setting.FontFamily, RichTextBox.Font.Size);
            #endregion

            #region PositionChoice
            switch (Profile.GetSetting("General", "PositionChoice").ToInteger(0)) {
                case 0:
                default: //default
                    this.StartPosition = FormStartPosition.WindowsDefaultBounds;
                    break;
                case 1: //store
                case 2: //custom
                    this.Location = new Point(
                        Profile.GetSetting("General", "PositionL").ToInteger(200),
                        Profile.GetSetting("General", "PositionT").ToInteger(200));
                    this.Size = new Size(
                        Profile.GetSetting("General", "PositionW").ToInteger(800),
                        Profile.GetSetting("General", "PositionH").ToInteger(600));
                    this.StartPosition = FormStartPosition.Manual;
                    scContainer.SplitterDistance = Profile.GetSetting("General", "UserlistW").ToInteger(250);
                    break;
            }
            m_LastPositionL = this.Left;
            m_LastPositionT = this.Top;
            m_LastPositionW = this.Width;
            m_LastPositionH = this.Height;
            #endregion

            #region StateChoice
            switch (Profile.GetSetting("General", "State").ToInteger(0)) {
                default:
                case 0: //Normal
                case 3: //Hidden
                    this.WindowState = FormWindowState.Normal;
                    break;
                case 1: //Maximized
                    this.WindowState = FormWindowState.Maximized;
                    break;
                case 2: //Minimized
                    this.WindowState = FormWindowState.Minimized;
                    break;
            }
            m_LastState = this.WindowState;
            #endregion
            #endregion

            this.Text = Profile.ProfileName + " - Offline";
        }

        public void Initialize() {
            RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Success, "Welcome to Felbot " + Properties.Resources.Version + " by Joe[x86] and Ribose!"));
            RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Success, "This bot is open source. Feel free to visit the project at: http://code.google.com/p/felbot/."));
            RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Success, "Profile " + Profile.ProfileName + " loaded."));

            if (Profile.GetSetting("General", "ConnectOnProfileStart").ToBoolean(false))
                mnuConnect.PerformClick();
        }

        private void frmProfile_FormClosing(object sender, FormClosingEventArgs e) {
            Profile.SetSetting("General", "UserlistW", scContainer.SplitterDistance);
            PacketThread.Socket_Disconnect();
            RichTextBox.Closing();
            Profile.Open = false;
        }
        #endregion

        #region Menustrip
        #region File
        private void mnuFileProfile_Click(object sender, EventArgs e) {
            Program.MainForm.EditProfile(m_Profile);
        }

        private void mnuFileClose_Click(object sender, EventArgs e) {
            this.Close();
        }
        #endregion

        #region Tools
        private void mnuToolsHashes_Click(object sender, EventArgs e) {
            Process.Start(Program.ApplicationFolder + Profile.GetSetting("AdvConn", "Hashes").ToString("\\Hashes\\"));
        }

        private void mnuToolsRefresh_Click(object sender, EventArgs e) {
            RefreshRtb();
        }

        private void mnuToolsClear_Click(object sender, EventArgs e) {
            ClearRtb();
        }

        private void mnuToolsHide_Click(object sender, EventArgs e) {
            Program.MainForm.HideProfile(this);
        }
        #endregion

        #region Connect
        /// <summary>
        /// This method is called when the "Connect" menu item is clicked.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void mnuConnect_Click(object sender, EventArgs e) {
            try {
                PacketThread.Socket_Connect();
            } catch (ArgumentOutOfRangeException m_eArgException) {
                RichTextBox.AddTextNodes(FCSControl.GetTextNode(FCSObjects.Chatroom_Bot_Fail, m_eArgException.ToString()));
            }
        }
        #endregion

        #region Disconnect
        private void mnuDisconnect_Click(object sender, EventArgs e) {
            PacketThread.Socket_Disconnect();
        }
        #endregion

        #region Channels
        private List<string> m_RecentChannels = new List<string>();
        private List<string> m_QuickChannels = new List<string>();
        private List<string> m_PublicChannels = new List<string>();

        /// <summary>A list of recent channels.</summary>
        public List<string> RecentChannels {
            get {
                return m_RecentChannels;
            }
        }

        /// <summary>A list of stored quick channels.</summary>
        public List<string> QuickChannels {
            get {
                return m_QuickChannels;
            }
        }

        /// <summary>A list of public channels.</summary>
        public List<string> PublicChannels {
            get {
                return m_PublicChannels;
            }
        }

        private void channels_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e) {
            if (e.ClickedItem.ToolTipText != "Click to add a Quickchannel to the list. Quickchannels can be accessed with an F-key (F2 through F24).")
                PacketThread.Send_SID_JOINCHANNEL(false, false, e.ClickedItem.Text);
        }

        private delegate void Profile_Delegate();

        /// <summary>Loads the quick channels from the global settings.</summary>
        public void LoadQuickChannels() {
            this.Invoke((Profile_Delegate) delegate() {
                mnuChannelsQuick.DropDownItems.Add((ToolStripItem) new ToolStripSeparator());
                ToolStripMenuItem tsmiAdd = (ToolStripMenuItem) mnuChannelsQuick.DropDownItems.Add("&Add Quickchannel");
                tsmiAdd.ToolTipText = "Click to add a Quickchannel to the list. Quickchannels can be accessed with an F-key (F2 through F24).";
                ToolStripTextBox tstbAdd = new ToolStripTextBox();
                mnuChannelsQuick.DropDownItems.Add(tstbAdd);
                tstbAdd.Visible = false;

                tsmiAdd.Click += new EventHandler(tsmiAdd_Click);
                tstbAdd.KeyPress += new KeyPressEventHandler(tstbAdd_KeyPress);

                m_QuickChannels = ProfileControl.Global.GetSettingStringList("QuickChannels", "Channel");
                for (int i = 0; i < m_QuickChannels.Count; i++) {
                    if (m_QuickChannels[i].Equals("") || m_QuickChannels[i] == null)
                        m_QuickChannels.RemoveAt(i);
                    for (int j = i + 1; j < m_QuickChannels.Count; j++) {
                        if (m_QuickChannels[i].Equals(m_QuickChannels[j])) {
                            m_QuickChannels.RemoveAt(j);
                        }
                    }
                }
                if (m_QuickChannels.Count > 23) {
                    MessageBox.Show("Another quick channel cannot be added.  Maximum of 23 reached.  To add more channels, please remove other channels with the DELETE key.",
                                    "Felbot",
                                    MessageBoxButtons.OK,
                                    MessageBoxIcon.Error);
                    return;
                }
                for (int i = 0; i < m_QuickChannels.Count; i++) {
                    if (i < 23)
                        AddQuickChannel(i + 1, m_QuickChannels[i]);
                    else
                        m_QuickChannels.RemoveAt(i);
                }
                ProfileControl.Global.SetSettingStringList("QuickChannels", "Channel", QuickChannels);
            });
        }

        private void tsmiAdd_Click(object sender, EventArgs e) {
            mnuChannels.ShowDropDown();
            mnuChannelsQuick.ShowDropDown();
            ToolStripMenuItem tsmiAdd = (ToolStripMenuItem) mnuChannelsQuick.DropDownItems[mnuChannelsQuick.DropDownItems.Count - 2];
            ToolStripTextBox tstbAdd = (ToolStripTextBox) mnuChannelsQuick.DropDownItems[mnuChannelsQuick.DropDownItems.Count - 1];
            tstbAdd.Text = "";
            tsmiAdd.Visible = false;
            tstbAdd.Visible = true;
        }

        private void tstbAdd_KeyPress(object sender, KeyPressEventArgs e) {
            if (e.KeyChar == '\x0D') {  //enter
                ToolStripMenuItem tsmiAdd = (ToolStripMenuItem) mnuChannelsQuick.DropDownItems[mnuChannelsQuick.DropDownItems.Count - 2];
                ToolStripTextBox tstbAdd = (ToolStripTextBox) mnuChannelsQuick.DropDownItems[mnuChannelsQuick.DropDownItems.Count - 1];
                tsmiAdd.Visible = true;
                tstbAdd.Visible = false;
                e.Handled = true;
                int count = mnuChannelsQuick.DropDownItems.Count - 2;
                if (count > 23) {
                    MessageBox.Show("Another quick channel cannot be added.  Maximum of 23 reached.  To add more channels, please remove other channels with the DELETE key.",
                                    "Felbot",
                                    MessageBoxButtons.OK,
                                    MessageBoxIcon.Error);
                    return;
                }
                if (QuickChannels.Contains(tstbAdd.Text)) {
                    MessageBox.Show("That channel cannot be added.  Another quick channel exists with that name.",
                                    "Felbot",
                                    MessageBoxButtons.OK,
                                    MessageBoxIcon.Error);
                    return;
                }
                if (tstbAdd.Text.Length == 0)
                    return;
                m_QuickChannels = ProfileControl.Global.GetSettingStringList("QuickChannels", "Channel");
                m_QuickChannels.Add(tstbAdd.Text);
                ProfileControl.Global.SetSettingStringList("QuickChannels", "Channel", QuickChannels);
                AddQuickChannel(count, tstbAdd.Text);
            }
        }

        private void mnuChannelsQuick_DropDownClosed(object sender, EventArgs e) {
            ToolStripMenuItem tsmiAdd = (ToolStripMenuItem) mnuChannelsQuick.DropDownItems[mnuChannelsQuick.DropDownItems.Count - 2];
            ToolStripTextBox tstbAdd = (ToolStripTextBox) mnuChannelsQuick.DropDownItems[mnuChannelsQuick.DropDownItems.Count - 1];
            tsmiAdd.Visible = true;
            tstbAdd.Visible = false;
        }

        private void AddQuickChannel(int number, string channelName) {
            ToolStripMenuItem tsItem = new ToolStripMenuItem(channelName);
            tsItem.ShortcutKeys = (Keys) (number + 112);
            mnuChannelsQuick.DropDownItems.Insert(number - 1, (ToolStripItem) tsItem);
        }

        /// <summary>Adds a recemt channel after joining it.</summary>
        /// <param name="a_sChannelName">The channel name.</param>
        public void AddRecentChannel(string channelName) {
            this.Invoke((Profile_Delegate) delegate() {
                if (RecentChannels.Contains(channelName)) {
                    int existsIndex = RecentChannels.IndexOf(channelName);
                    RecentChannels.RemoveAt(existsIndex);
                    mnuChannelsRecent.DropDownItems.RemoveAt(existsIndex);
                }
                RecentChannels.Add(channelName);
                ToolStripItem tsItem = mnuChannelsRecent.DropDownItems.Add(channelName);
            });
        }

        /// <summary>Adds a public channel when Battle.net alerts the bot of it.</summary>
        /// <param name="a_sChannelName">The channel name,</param>
        public void AddPublicChannel(string channelName) {
            if (channelName.Equals(""))
                return;
            this.Invoke((Profile_Delegate) delegate() {
                PublicChannels.Add(channelName);
                ToolStripItem tsItem = mnuChannelsPublic.DropDownItems.Add(channelName);
            });
        }

        /// <summary>Clears the three channel lists when the bot logs off, so it can't send a packet while offline.</summary>
        public void ClearChannels() {
            this.Invoke((Profile_Delegate) delegate() {
                mnuChannelsQuick.DropDownItems.Clear();
                mnuChannelsRecent.DropDownItems.Clear();
                mnuChannelsPublic.DropDownItems.Clear();
                QuickChannels.Clear();
                RecentChannels.Clear();
                PublicChannels.Clear();
            });
        }
        #endregion
        #endregion

        #region Context Menus
        #region Text Context Menu
        private void mnuText_Opening(object sender, System.ComponentModel.CancelEventArgs e) {
            Control source = ((Control) mnuText.SourceControl);
            if (source.Equals(rtbChat)) {
                mnuTextCut.Enabled = false;
                mnuTextCopy.Enabled = (rtbChat.SelectionLength > 0);
                mnuTextPaste.Enabled = false;
                mnuTextDelete.Enabled = false;
            } else if (source.Equals(txtSend)) {
                mnuTextCut.Enabled = (txtSend.SelectionLength > 0);
                mnuTextCopy.Enabled = (txtSend.SelectionLength > 0);
                mnuTextPaste.Enabled = (Clipboard.ContainsText());
                mnuTextDelete.Enabled = (txtSend.SelectionLength > 0);
            }
        }

        private void mnuTextCut_Click(object sender, EventArgs e) {
            Control source = ((Control) mnuText.SourceControl);
            if (source == null) //ctrl-x
            {
                if (rtbChat.Focused)
                    source = (Control) rtbChat;
                else if (txtSend.Focused)
                    source = (Control) txtSend;
                else
                    return;
            }
            if (source.Equals(txtSend)) {
                txtSend.Cut();
            }
        }

        private void mnuTextCopy_Click(object sender, EventArgs e) {
            Control source = ((Control) mnuText.SourceControl);
            if (source == null) //ctrl-c
            {
                if (rtbChat.Focused)
                    source = (Control) rtbChat;
                else if (txtSend.Focused)
                    source = (Control) txtSend;
                else
                    return;
            }
            if (source.Equals(rtbChat)) {
                rtbChat.Copy();
            } else if (source.Equals(txtSend)) {
                txtSend.Copy();
            }
        }

        private void mnuTextPaste_Click(object sender, EventArgs e) {
            Control source = ((Control) mnuText.SourceControl);
            if (source == null) //ctrl-v
            {
                if (rtbChat.Focused)
                    source = (Control) rtbChat;
                else if (txtSend.Focused)
                    source = (Control) txtSend;
                else
                    return;
            }
            if (source.Equals(txtSend)) {
                txtSend.Paste();
            }
        }

        private void mnuTextDelete_Click(object sender, EventArgs e) {
            Control source = ((Control) mnuText.SourceControl);
            if (source == null) //del
            {
                if (rtbChat.Focused)
                    source = (Control) rtbChat;
                else if (txtSend.Focused)
                    source = (Control) txtSend;
                else
                    return;
            }
            if (source.Equals(txtSend)) {
                txtSend.Delete();
            }
        }

        private void mnuTextSelectAll_Click(object sender, EventArgs e) {
            Control source = ((Control) mnuText.SourceControl);
            if (source == null) //ctrl-a
            {
                if (rtbChat.Focused)
                    source = (Control) rtbChat;
                else if (txtSend.Focused)
                    source = (Control) txtSend;
                else
                    return;
            }
            if (source.Equals(rtbChat)) {
                rtbChat.SelectAll();
            } else if (source.Equals(txtSend)) {
                txtSend.SelectAll();
            }
        }
        #endregion

        #region User Context Menu
        private void mnuUser_Opening(object sender, System.ComponentModel.CancelEventArgs e) {
            #region Hide All
            mnuUserWhois.Visible = false;
            mnuUserProfile.Visible = false;
            mnuUserStats.Visible = false;
            mnuUserProfile.Visible = false;
            mnuUserWhisper.Visible = false;

            mnuChannelUserSeparator.Visible = false;

            mnuChannelUserBan.Visible = false;
            mnuChannelUserKick.Visible = false;
            mnuChannelUserDesignate.Visible = false;
            mnuChannelUserIgnore.Visible = false;
            mnuChannelUserUnignore.Visible = false;
            mnuChannelUserClanInvite.Visible = false;
            mnuChannelUserFriendAdd.Visible = false;

            mnuChannelSeparator.Visible = false;

            mnuChannelRejoin.Visible = false;

            mnuFriendsUserSeparator.Visible = false;

            mnuFriendsUserPromote.Visible = false;
            mnuFriendsUserDemote.Visible = false;
            mnuFriendsUserRemove.Visible = false;

            mnuFriendsSeparator.Visible = false;

            mnuFriendsAdd.Visible = false;
            mnuFriendsMessage.Visible = false;

            mnuClanUserSeparator.Visible = false;

            mnuClanUserPromote.Visible = false;
            mnuClanUserDemote.Visible = false;
            mnuClanUserRemove.Visible = false;

            mnuClanSeparator.Visible = false;

            mnuClanCreate.Visible = false;
            mnuClanLeave.Visible = false;
            mnuClanDisband.Visible = false;
            mnuClanSetMotd.Visible = false;
            #endregion

            Control source = ((Control) mnuUser.SourceControl);
            if (source.Equals(lvChannel)) {
                if (lvChannel.SelectedItems.Count > 0) {
                    mnuUserWhois.Visible = true;
                    mnuUserProfile.Visible = true;
                    mnuUserStats.Visible = true;
                    mnuUserProfile.Visible = true;
                    mnuUserWhisper.Visible = true;
                    mnuUserWhisper.Enabled = (txtSend.Text.Length > 0);

                    mnuChannelUserSeparator.Visible = true;

                    mnuChannelUserBan.Visible = true;
                    mnuChannelUserBan.Enabled = (Channel.You.HasOps);
                    mnuChannelUserKick.Visible = true;
                    mnuChannelUserKick.Enabled = (Channel.You.HasOps);
                    mnuChannelUserDesignate.Visible = true;
                    mnuChannelUserDesignate.Enabled = (Channel.You.HasOps);
                    mnuChannelUserIgnore.Visible = true;
                    mnuChannelUserUnignore.Visible = true;
                    mnuChannelUserClanInvite.Visible = true;
                    mnuChannelUserFriendAdd.Visible = true;

                    mnuChannelSeparator.Visible = true;
                }

                mnuChannelRejoin.Visible = true;
            } else if (source.Equals(lvFriends)) {
                if (lvFriends.SelectedItems.Count > 0) {
                    mnuUserWhois.Visible = true;
                    mnuUserProfile.Visible = true;
                    mnuUserStats.Visible = true;
                    mnuUserProfile.Visible = true;
                    mnuUserWhisper.Visible = true;
                    mnuUserWhisper.Enabled = (txtSend.Text.Length > 0);

                    mnuFriendsUserSeparator.Visible = true;

                    mnuFriendsUserPromote.Visible = true;
                    mnuFriendsUserDemote.Visible = true;
                    mnuFriendsUserRemove.Visible = true;

                    mnuFriendsSeparator.Visible = true;
                }

                mnuFriendsAdd.Visible = true;
                mnuFriendsAdd.Enabled = (txtSend.Text.Length > 0);
                mnuFriendsMessage.Visible = true;
                mnuFriendsMessage.Enabled = (txtSend.Text.Length > 0);
            } else if (source.Equals(lvClan)) {
                if (lvClan.SelectedItems.Count > 0) {
                    mnuUserWhois.Visible = true;
                    mnuUserProfile.Visible = true;
                    mnuUserStats.Visible = true;
                    mnuUserProfile.Visible = true;
                    mnuUserWhisper.Visible = true;
                    mnuUserWhisper.Enabled = (txtSend.Text.Length > 0);

                    mnuClanUserSeparator.Visible = true;

                    mnuClanUserPromote.Visible = true;
                    mnuClanUserDemote.Visible = true;
                    mnuClanUserRemove.Visible = true;

                    mnuClanSeparator.Visible = true;
                }

                mnuClanCreate.Visible = true;
                mnuClanLeave.Visible = true;
                mnuClanDisband.Visible = true;
                mnuClanSetMotd.Visible = true;
                mnuClanSetMotd.Enabled = (txtSend.Text.Length > 0);
            }
        }

        private void mnuUserWhois_Click(object sender, EventArgs e) {
            string d2Star = "";
            if (PacketThread.Client.Equals("D2DV") || PacketThread.Client.Equals("D2XP"))
                d2Star = "*";
            Control source = ((Control) mnuUser.SourceControl);
            if (source.Equals(lvChannel)) {
                foreach (ListViewItem user in lvChannel.SelectedItems) {
                    PacketThread.AddQueue("/whois " + d2Star + user.Text);
                }
            } else if (source.Equals(lvFriends)) {
                foreach (ListViewItem friend in lvFriends.SelectedItems) {
                    PacketThread.AddQueue("/whois " + d2Star + friend.Text);
                }
            } else if (source.Equals(lvClan)) {
                foreach (ListViewItem member in lvClan.SelectedItems) {
                    PacketThread.AddQueue("/whois " + member.Text);
                }
            }
        }

        private void mnuUserProfile_Click(object sender, EventArgs e) {
            //not implemented yet;
        }

        private void mnuUserStats_Click(object sender, EventArgs e) {
            Control source = ((Control) mnuUser.SourceControl);
            if (source.Equals(lvChannel)) {
                foreach (ListViewItem user in lvChannel.SelectedItems) {
                    switch (Channel.GetUser(user.Text).StatString.ClientCode) {
                        case "STAR":
                            PacketThread.AddQueue("/stats " + user.Text + " STAR");
                            break;
                        case "SEXP":
                            PacketThread.AddQueue("/stats " + user.Text + " SEXP");
                            break;
                        case "WAR3":
                            PacketThread.AddQueue("/stats " + user.Text + " WAR3");
                            break;
                        case "W3XP":
                            PacketThread.AddQueue("/stats " + user.Text + " W3XP");
                            break;
                        default:
                            RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Fail, user.Text + " is not on a client that has stats."));
                            break;
                    }
                }
            } else if (source.Equals(lvFriends)) {
                foreach (ListViewItem friend in lvFriends.SelectedItems) {
                    switch (Friends.GetUser(friend.Text).Product) {
                        case "STAR":
                            PacketThread.AddQueue("/stats " + friend.Text + " STAR");
                            break;
                        case "SEXP":
                            PacketThread.AddQueue("/stats " + friend.Text + " SEXP");
                            break;
                        case "WAR3":
                            PacketThread.AddQueue("/stats " + friend.Text + " WAR3");
                            break;
                        case "W3XP":
                            PacketThread.AddQueue("/stats " + friend.Text + " W3XP");
                            break;
                        default:
                            RichTextBox.AddTextNodes(FCSControl.GetTextNode(FCSObjects.Chatroom_Bot_Fail, friend.Text + " is not on a client that has stats, or is offline."));
                            break;
                    }
                }
            } else if (source.Equals(lvClan)) {
                switch (PacketThread.Client.ProductID) {
                    case "WAR3":
                        foreach (ListViewItem member in lvClan.SelectedItems) {
                            PacketThread.AddQueue("/stats " + member.Text + " WAR3");
                        }
                        break;
                    case "W3XP":
                        foreach (ListViewItem member in lvClan.SelectedItems) {
                            PacketThread.AddQueue("/stats " + member.Text + " W3XP");
                        }
                        break;
                }
            }
        }

        private void mnuUserWhisper_Click(object sender, EventArgs e) {
            if (txtSend.Text.Length == 0)
                return;
            string d2Star = "";
            if (PacketThread.Client.Equals("D2DV") || PacketThread.Client.Equals("D2XP"))
                d2Star = "*";
            Control source = ((Control) mnuUser.SourceControl);
            if (source.Equals(lvChannel)) {
                foreach (ListViewItem user in lvChannel.SelectedItems) {
                    PacketThread.AddQueue("/w " + d2Star + user.Text + " " + txtSend.Text);
                }
            } else if (source.Equals(lvFriends)) {
                foreach (ListViewItem friend in lvFriends.SelectedItems) {
                    PacketThread.AddQueue("/w " + d2Star + friend.Text + " " + txtSend.Text);
                }
            } else if (source.Equals(lvClan)) {
                foreach (ListViewItem member in lvClan.SelectedItems) {
                    PacketThread.AddQueue("/w " + member.Text + " " + txtSend.Text);
                }
            }
            txtSend.Text = "";
        }

        private void mnuChannelUserBan_Click(object sender, EventArgs e) {
            if (Channel.You.HasOps) {
                string d2Star = "";
                if (PacketThread.Client.Equals("D2DV") || PacketThread.Client.Equals("D2XP"))
                    d2Star = "*";
                Control source = ((Control) mnuUser.SourceControl);
                if (source.Equals(lvChannel)) {
                    foreach (ListViewItem user in lvChannel.SelectedItems) {
                        PacketThread.AddQueue("/ban " + d2Star + user.Text);
                    }
                }
            } else {
                RichTextBox.AddTextNodes(FCSControl.GetTextNode(FCSObjects.Chatroom_Bot_Fail, "The bot is not a channel operator."));
            }
        }

        private void mnuChannelUserKick_Click(object sender, EventArgs e) {
            if (Channel.You.HasOps) {
                string d2Star = "";
                if (PacketThread.Client.Equals("D2DV") || PacketThread.Client.Equals("D2XP"))
                    d2Star = "*";
                Control source = ((Control) mnuUser.SourceControl);
                if (source.Equals(lvChannel)) {
                    foreach (ListViewItem user in lvChannel.SelectedItems) {
                        PacketThread.AddQueue("/kick " + d2Star + user.Text);
                    }
                }
            } else {
                RichTextBox.AddTextNodes(FCSControl.GetTextNode(FCSObjects.Chatroom_Bot_Fail, "The bot is not a channel operator."));
            }
        }

        private void mnuChannelUserDesignate_Click(object sender, EventArgs e) {
            if (Channel.You.HasOps) {
                string d2Star = "";
                if (PacketThread.Client.Equals("D2DV") || PacketThread.Client.Equals("D2XP"))
                    d2Star = "*";
                Control m_conSource = ((Control) mnuUser.SourceControl);
                if (m_conSource.Equals(lvChannel)) {
                    foreach (ListViewItem user in lvChannel.SelectedItems) {
                        PacketThread.AddQueue("/designate " + d2Star + user.Text);
                    }
                }
            } else {
                RichTextBox.AddTextNodes(FCSControl.GetTextNode(FCSObjects.Chatroom_Bot_Fail, "The bot is not a channel operator."));
            }
        }

        private void mnuChannelUserIgnore_Click(object sender, EventArgs e) {
            string d2Star = "";
            if (PacketThread.Client.Equals("D2DV") || PacketThread.Client.Equals("D2XP"))
                d2Star = "*";
            Control m_conSource = ((Control) mnuUser.SourceControl);
            if (m_conSource.Equals(lvChannel)) {
                foreach (ListViewItem user in lvChannel.SelectedItems) {
                    PacketThread.AddQueue("/squelch " + d2Star + user.Text);
                }
            }
        }

        private void mnuChannelUserUnignore_Click(object sender, EventArgs e) {
            string d2Star = "";
            if (PacketThread.Client.Equals("D2DV") || PacketThread.Client.Equals("D2XP"))
                d2Star = "*";
            Control m_conSource = ((Control) mnuUser.SourceControl);
            if (m_conSource.Equals(lvChannel)) {
                foreach (ListViewItem user in lvChannel.SelectedItems) {
                    PacketThread.AddQueue("/unsquelch " + d2Star + user.Text);
                }
            }
        }

        private void mnuChannelUserClanInvite_Click(object sender, EventArgs e) {
            if (PacketThread.Client.Equals("WAR3") || PacketThread.Client.Equals("W3XP")) {
                if (Clan.ClanTag != "") {
                    Control source = ((Control) mnuUser.SourceControl);
                    if (source.Equals(lvChannel)) {
                        foreach (ListViewItem user in lvChannel.SelectedItems) {
                            PacketThread.Send_SID_CLANINVITATION(ClanQueueMember.GenerateCookie(), user.Text);
                            RichTextBox.AddTextNodes(FCSControl.GetTextNode(FCSObjects.Chatroom_Information_Clan, "[CLAN] Inviting " + user.Text + " to join Clan " + Clan.ClanTag + "."));
                        }
                    }
                } else {
                    RichTextBox.AddTextNodes(FCSControl.GetTextNode(FCSObjects.Chatroom_Bot_Fail, "The bot must be in a clan to invite someone."));
                }
            } else {
                RichTextBox.AddTextNodes(FCSControl.GetTextNode(FCSObjects.Chatroom_Bot_Fail, "The bot must be on WarCraft III to invite someone."));
            }
        }

        private void mnuChannelUserFriendAdd_Click(object sender, EventArgs e) {
            Control source = ((Control) mnuUser.SourceControl);
            if (source.Equals(lvChannel)) {
                foreach (ListViewItem user in lvChannel.SelectedItems) {
                    PacketThread.AddQueue("/f a " + user.Text);
                }
            }
        }

        private void mnuChannelRejoin_Click(object sender, EventArgs e) {
            string rejoinThis = Channel.ChannelName;
            PacketThread.AddQueue("/join Felbot " + PacketThread.UniqueUsername + " ReJoin");
            PacketThread.AddQueue("/join " + rejoinThis);
        }

        private void mnuFriendsUserPromote_Click(object sender, EventArgs e) {
            Control source = ((Control) mnuUser.SourceControl);
            if (source.Equals(lvFriends)) {
                foreach (ListViewItem friend in lvFriends.SelectedItems) {
                    PacketThread.AddQueue("/f p " + friend.Text);
                }
            }
        }

        private void mnuFriendsUserDemote_Click(object sender, EventArgs e) {
            Control source = ((Control) mnuUser.SourceControl);
            if (source.Equals(lvFriends)) {
                foreach (ListViewItem friend in lvFriends.SelectedItems) {
                    PacketThread.AddQueue("/f d " + friend.Text);
                }
            }
        }

        private void mnuFriendsUserRemove_Click(object sender, EventArgs e) {
            Control source = ((Control) mnuUser.SourceControl);
            if (source.Equals(lvFriends)) {
                foreach (ListViewItem friend in lvFriends.SelectedItems) {
                    PacketThread.AddQueue("/f r " + friend.Text);
                }
            }
        }

        private void mnuFriendsAdd_Click(object sender, EventArgs e) {
            if (txtSend.Text.Length == 0)
                return;
            PacketThread.AddQueue("/f a " + txtSend.Text);
            txtSend.Text = "";
        }

        private void mnuFriendsMessage_Click(object sender, EventArgs e) {
            if (txtSend.Text.Length == 0)
                return;
            PacketThread.AddQueue("/f m " + txtSend.Text);
            txtSend.Text = "";
        }

        private void mnuClanUserPromote_Click(object sender, EventArgs e) {
            Control source = ((Control) mnuUser.SourceControl);
            if (source.Equals(lvClan)) {
                byte oldRank;
                foreach (ListViewItem member in lvClan.SelectedItems) {
                    oldRank = (byte) Clan.GetUser(member.Text).Rank;
                    if (oldRank < 3 && oldRank > 0) {
                        PacketThread.Send_SID_CLANRANKCHANGE(ClanQueueMember.GenerateCookie(), member.Text, (byte) (oldRank + 1));
                        RichTextBox.AddTextNodes(FCSControl.GetTextNode(FCSObjects.Chatroom_Information_Clan, "[CLAN] Promoting " + member.Text + " to a " + Clan.GetClanRank((byte) (oldRank + 1)) + "."));
                    } else {
                        RichTextBox.AddTextNodes(FCSControl.GetTextNode(FCSObjects.Chatroom_Bot_Fail, "[CLAN] Cannot promote " + member.Text + " because he is a " + Clan.GetClanRank(oldRank) + "."));
                    }
                }
            }
        }

        private void mnuClanUserDemote_Click(object sender, EventArgs e) {
            Control source = ((Control) mnuUser.SourceControl);
            if (source.Equals(lvClan)) {
                byte oldRank;
                foreach (ListViewItem member in lvClan.SelectedItems) {
                    oldRank = (byte) Clan.GetUser(member.Text).Rank;
                    if (oldRank < 4 && oldRank > 1) {
                        PacketThread.Send_SID_CLANRANKCHANGE(ClanQueueMember.GenerateCookie(), member.Text, (byte) (oldRank - 1));
                        RichTextBox.AddTextNodes(FCSControl.GetTextNode(FCSObjects.Chatroom_Information_Clan, "[CLAN] Demoting " + member.Text + " to a " + Clan.GetClanRank((byte) (oldRank - 1)) + "."));
                    } else {
                        RichTextBox.AddTextNodes(FCSControl.GetTextNode(FCSObjects.Chatroom_Bot_Fail, "[CLAN] Cannot demote " + member.Text + " because he is a " + Clan.GetClanRank(oldRank) + "."));
                    }
                }
            }
        }

        private void mnuClanUserRemove_Click(object sender, EventArgs e) {
            Control source = ((Control) mnuUser.SourceControl);
            if (source.Equals(lvClan)) {
                byte oldRank;
                foreach (ListViewItem member in lvClan.SelectedItems) {
                    oldRank = (byte) Clan.GetUser(member.Text).Rank;
                    if (oldRank < 4 && oldRank > 0) {
                        PacketThread.Send_SID_CLANREMOVEMEMBER(ClanQueueMember.GenerateCookie(), member.Text);
                        RichTextBox.AddTextNodes(FCSControl.GetTextNode(FCSObjects.Chatroom_Information_Clan, "[CLAN] Removing " + member.Text + " from the clan."));
                    } else {
                        RichTextBox.AddTextNodes(FCSControl.GetTextNode(FCSObjects.Chatroom_Bot_Fail, "[CLAN] Cannot remove " + member.Text + " because he is a " + Clan.GetClanRank(oldRank) + "."));
                    }
                }
            }
        }

        private void mnuClanCreate_Click(object sender, EventArgs e) {
            Control source = ((Control) mnuUser.SourceControl);
            if (source.Equals(lvClan)) {
                /*
                if (txtSend.Text.Length < 4)
                    return;
                string clanTag = txtSend.Text.Split(':')[0];
                string clanName = txtSend.Text.Split(':')[1];
                ClanList.ClanTag = clanTag;
                ClanList.ClanName = clanName;
                RichTextBox.AddTextNodes(FCSControl.GetTextNode(FCSObjects.Chatroom_Information_Clan, "[CLAN] Showing available users for clan invitation.."));
                PacketThread.Send_SID_CLANFINDCANDIDATES(ClanQueueMember.GenerateCookie(), clanTag);*/
            }
        }

        private void mnuClanLeave_Click(object sender, EventArgs e) {
            Control source = ((Control) mnuUser.SourceControl);
            if (source.Equals(lvClan)) {
                if (MessageBox.Show("Are you sure you want to leave the clan? This action is not undoable.",
                                    "Felbot",
                                    MessageBoxButtons.YesNo,
                                    MessageBoxIcon.Exclamation,
                                    MessageBoxDefaultButton.Button2)
                        == DialogResult.Yes) {
                    PacketThread.Send_SID_CLANREMOVEMEMBER(ClanQueueMember.GenerateCookie(), PacketThread.UniqueUsername.Split('#')[0]);
                    RichTextBox.AddTextNodes(FCSControl.GetTextNode(FCSObjects.Chatroom_Information_Clan, "[CLAN] Leaving clan.."));
                }
            }
        }

        private void mnuClanDisband_Click(object sender, EventArgs e) {
            Control source = ((Control) mnuUser.SourceControl);
            if (source.Equals(lvClan)) {
                if (MessageBox.Show("Are you sure you want to disband the clan? This action is not undoable.",
                                    "Felbot",
                                    MessageBoxButtons.YesNo,
                                    MessageBoxIcon.Exclamation,
                                    MessageBoxDefaultButton.Button2)
                        == DialogResult.Yes) {
                    PacketThread.Send_SID_CLANDISBAND(ClanQueueMember.GenerateCookie());
                    RichTextBox.AddTextNodes(FCSControl.GetTextNode(FCSObjects.Chatroom_Information_Clan, "[CLAN] Disbanding clan.."));
                }
            }
        }

        private void mnuClanSetMotd_Click(object sender, EventArgs e) {
            Control source = ((Control) mnuUser.SourceControl);
            if (source.Equals(lvClan)) {
                if (txtSend.Text.Length == 0)
                    return;
                PacketThread.Send_SID_CLANSETMOTD(ClanQueueMember.GenerateCookie(), txtSend.Text);
                RichTextBox.AddTextNodes(FCSControl.GetTextNode(FCSObjects.Chatroom_Information_Clan, "[CLAN] Attempted to set clan MOTD."));
                txtSend.Text = "";
            }
        }
        #endregion
        #endregion

        #region Tooltips
        private void listheader_MouseHover(object sender, EventArgs e) {
            tip.Hide(this);
            tip.ToolTipTitle = ((Label) sender).Text;
            tip.Show(((Label) sender).Tag.ToString(), this, this.PointToClient(Control.MousePosition + new Size(5, 40)), 5000);
        }

        private void listview_ItemMouseHover(object sender, ListViewItemMouseHoverEventArgs e) {
            tip.Hide(this);
            tip.ToolTipTitle = e.Item.Text;
            tip.Show(e.Item.ToolTipText, this, this.PointToClient(Control.MousePosition + new Size(5, 40)), 5000);
        }

        private void listviewheader_MouseLeave(object sender, EventArgs e) {
            tip.Hide(this);
        }
        #endregion

        #region Column Size
        private void scContainer_SplitterMoved(object sender, SplitterEventArgs e) {
            ResizeColumns();
        }

        private void frmProfile_ResizeEnd(object sender, EventArgs e) {
            if (this.WindowState == FormWindowState.Normal) {
                if (Profile.GetSetting("General", "PositionChoice").ToInteger(0) == 1) {
                    //store
                    Profile.SetSetting("General", "PositionL", this.Left);
                    Profile.SetSetting("General", "PositionT", this.Top);
                    Profile.SetSetting("General", "PositionW", this.Width);
                    Profile.SetSetting("General", "PositionH", this.Height);
                    Profile.SaveSettings();
                }
            }
            ResizeColumns();
        }

        private void ResizeColumns() {
            if (Profile.GetSetting("General", "PositionChoice").ToInteger(0) == 1) {
                //store
                Profile.SetSetting("General", "UserlistW", scContainer.SplitterDistance);
                Profile.SaveSettings();
            }
            colChannel.Width = scContainer.Panel2.Width - 160;
            colFriends.Width = scContainer.Panel2.Width - 60;
            colClan.Width = scContainer.Panel2.Width - 60;
        }
        #endregion

        #region Rich Text Box
        /// <summary>
        /// Call this to tell the profile form that the FCS settings have changed, and the RTB should be refreshed.
        /// </summary>
        public void RefreshRtb() {
            if (m_Started < DateTime.Today)
                m_Started = DateTime.Today;
            RichTextBox.RefreshText(
                m_Started,
                (ProfileControl.Global.GetSetting("Interface", "RTBMaxLines").ToBoolean(true) ?
                ProfileControl.Global.GetSetting("Interface", "RTBMaxLinesNumber").ToInteger(500) :
                -1));
        }

        private void ClearRtb() {
            m_Started = DateTime.Now;
            RichTextBox.Clear();
            RichTextBox.AddTextNodes(new TextNode(FCSObjects.Chatroom_Bot_Success, "Chat cleared."));
        }
        #endregion

        #region Public Methods
        /// <summary>
        /// Selects the clan tab.
        /// </summary>
        public void SelectClanTab() {
            tcChannel.SelectTab(2);
        }

        /// <summary>
        /// Adds a control to the currently shown tab page.
        /// </summary>
        /// <param name="control">The control to add.</param>
        public void AddControlToUserList(Control control) {
            tcChannel.SelectedTab.Controls.Add(control);
        }
        #endregion
    }
}
